package com.songlanyun.modules.like.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.songlanyun.common.enums.OpusConstant;
import com.songlanyun.common.exception.RRException;
import com.songlanyun.common.utils.*;
import com.songlanyun.common.validator.ValidatorUtils;
import com.songlanyun.modules.account.entity.UserInfoEntity;
import com.songlanyun.modules.account.service.UserInfoService;
import com.songlanyun.modules.article.entity.Article;
import com.songlanyun.modules.article.service.ArticleService;
import com.songlanyun.modules.browse.entity.BrowseRecord;
import com.songlanyun.modules.comment.model.vo.CommentVO;
import com.songlanyun.modules.exception.BbsException;
import com.songlanyun.modules.like.model.vo.MyLikeVO;
import com.songlanyun.modules.opus.entity.Opus;
import com.songlanyun.modules.opus.service.OpusService;
import com.songlanyun.modules.rabbitmq.util.SpringContextUtil;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.songlanyun.modules.like.dao.LikeRecordDao;
import com.songlanyun.modules.like.entity.LikeRecord;
import com.songlanyun.modules.like.service.LikeRecordService;

import javax.annotation.Resource;


@Service("likeRecordService")
public class LikeRecordServiceImpl extends ServiceImpl<LikeRecordDao, LikeRecord> implements LikeRecordService {

    @Resource
    private RedisUtils redisUtils;
    @Resource
    private UserInfoService userInfoService;
    @Resource
    private OpusService opusService;
    @Resource
    private ArticleService articleService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<LikeRecord> page = this.page(
                new Query<LikeRecord>().getPage(params),
                new QueryWrapper<LikeRecord>()
        );

        return new PageUtils(page);
    }

    @Override
    public Boolean like(OpusConstant.ModelType modelType, Long modelId, Long likeUserId, Long publisherId, Date time) {
        //一个用户对同一类型的点赞只记录一次
        LikeRecord record = this.baseMapper.selectOne(
                new LambdaQueryWrapper<LikeRecord>()
                        .eq(LikeRecord::getModelType, modelType)
                        .eq(LikeRecord::getModelId, modelId)
                        .eq(LikeRecord::getLikeUserId, likeUserId)
                        .last("limit 1")
        );
        if (record == null) {
            //保存点赞记录
            record = new LikeRecord(modelType, modelId, likeUserId, publisherId, time);
            ValidatorUtils.validateEntity(record);
            this.baseMapper.insert(record);
            return true;
        } else {
            record.setLastTime(time);
            this.baseMapper.updateById(record);
            return false;
        }

    }

    @Override
    public void delLike(Long userId, OpusConstant.ModelType modelType, Long modelId) {
        this.baseMapper.delete(
                new LambdaQueryWrapper<LikeRecord>()
                        .eq(LikeRecord::getModelType, modelType)
                        .eq(LikeRecord::getModelId, modelId)
                        .eq(LikeRecord::getLikeUserId, userId)
        );

    }

    @Override
    public PageUtils myPage(Map<String, Object> params) {
        IPage<MyLikeVO> page = this.baseMapper.myPage(new Query<LikeRecord>().getPage(params), params);
        //查询发布人
        page.getRecords().forEach(m -> {
            if (OpusConstant.ModelType.OPUS.equals(m.getModelType())) {
                UserInfoEntity userInfoEntity = userInfoService.getById(m.getUserId());
                if (userInfoEntity != null) {
                    m.setNickname(userInfoEntity.loadResRealName());
                    m.setHeadPhoto(userInfoEntity.getHeadPhoto());
                }
            }
            //获取点赞总数
            Integer likeSum = likeSum(m.getModelType(), m.getModelId());
            m.setLikeNum(likeSum);
        });

        return new PageUtils(page);
    }

    @Override
    public IPage<MyLikeVO> myLikePage(HashMap<String, Object> params) {

        return this.baseMapper.myPage(new Query<LikeRecord>().getPage(params), params);
    }

    @Override
    public Integer likeSumByUserId(Long userId) {
        return this.baseMapper.selectCount(
                new LambdaQueryWrapper<LikeRecord>()
                        .eq(LikeRecord::getModelExist, true)
                        .eq(LikeRecord::getLikeUserId, userId)
        );
    }

    @Override
    public Boolean isLike(Long userId, OpusConstant.ModelType modelType, Long modelId) {
        Integer b = this.baseMapper.selectCount(
                new LambdaQueryWrapper<LikeRecord>()
                        .eq(LikeRecord::getLikeUserId, userId)
                        .eq(LikeRecord::getModelType, modelType)
                        .eq(LikeRecord::getModelId, modelId)
        );
        return b > 0;
    }

    /**
     * 删除redis缓存
     *
     * @param userId
     * @param bbsKey
     * @param modelId
     */
    @Override
    public Boolean delLikeRedis(Long userId, RedisKeys.BbsKey bbsKey, Long modelId) {
        String userIdStr = String.valueOf(userId);
        String modelIdStr = String.valueOf(modelId);
        //取redis缓存
        BoundHashOperations<String, String, Object> data = redisUtils.boundHashOps(bbsKey.getKey());
        HashMap<String, Object> userMap = (HashMap<String, Object>) data.get(modelIdStr);
        if (userMap != null && userMap.containsKey(userIdStr)) {
            userMap.remove(userIdStr);
            data.put(modelIdStr, userMap);
            return true;
        }

        return false;
    }

    @Override
    public Integer likeSum(OpusConstant.ModelType modelType, Long modelId) {
        String bbsKey = "";
        String modelStr = String.valueOf(modelId);
        Integer likeNum = 0;
        switch (modelType) {
            case OPUS:
                bbsKey = RedisKeys.BbsKey.LIKE_OPUS_KEY.getKey();
                Opus opus = opusService.getById(modelId);
                if (opus != null) {
                    likeNum = opus.getLikeNum();
                }
                break;
            case ARTICLE:
                bbsKey = RedisKeys.BbsKey.LIKE_ARTICLE_KEY.getKey();
                Article article = articleService.getById(modelId);
                if (article != null) {
                    likeNum = article.getLikeNum();
                }
                break;
        }
        //先查redis，再查数据库
        RedisUtils redisUtils = (RedisUtils) SpringContextUtil.getBean("redisUtils");
        BoundHashOperations<String, String, Object> data = redisUtils.boundHashOps(bbsKey);
        HashMap<String, Object> userMap = (HashMap<String, Object>) data.get(modelStr);

        int redisLikeNum = 0;
        if (userMap != null) {
            redisLikeNum = userMap.keySet().size();
        }

        return Math.toIntExact(likeNum + redisLikeNum);

    }

    @Override
    public void modelDel(OpusConstant.ModelType modelType, Long modelId) {
        this.update(
                new LambdaUpdateWrapper<LikeRecord>()
                        .eq(LikeRecord::getModelType, modelType)
                        .eq(LikeRecord::getModelId, modelId)
                        .set(LikeRecord::getModelExist, false)
        );
    }

    private Boolean ifLike(OpusConstant.ModelType modelType, Long modelId, Long likeUserId) {

        Integer count = this.baseMapper.selectCount(
                new LambdaQueryWrapper<LikeRecord>()
                        .eq(LikeRecord::getModelType, modelType)
                        .eq(LikeRecord::getModelId, modelId)
                        .eq(LikeRecord::getLikeUserId, likeUserId)
        );

        return count > 0;
    }


}
